from flask import request, jsonify, Blueprint
from app.models.transactions import Transaction
from app.models.categories import Category
from app.models.budgets import Budget
from app.extensions import db
from app.routes.auth import token_required
from sqlalchemy import func, case
from datetime import datetime
import numpy as np
from datetime import timedelta
# from app import logger
import traceback

# 创建蓝图（与transaction.py保持一致的命名风格）
statistics_bp = Blueprint('statistics', __name__)


# 1. 月度/年度收支概览
@statistics_bp.route('/overview', methods=["GET"])  # 简化路由路径，与蓝图配合使用
@token_required
def get_statistics_overview(current_user):
    try:
        # 获取参数（使用current_user获取user_id）
        time_type = request.args.get("time_type", "month")
        year = request.args.get("year")
        month = request.args.get("month")

        # 参数校验
        if not all([time_type, year]):
            return jsonify({"code": 400, "msg": "time_type、year 为必传项", "data": None}), 400
        if time_type not in ["month", "year"]:
            return jsonify({"code": 400, "msg": "time_type 仅支持 'month' 或 'year'", "data": None}), 400
        if time_type == "month" and (not month or not 1 <= int(month) <= 12):
            return jsonify({"code": 400, "msg": "月度统计需传 1-12 的 month 参数", "data": None}), 400

        year = int(year)
        month = int(month) if time_type == "month" else None

        # 按时间粒度筛选数据
        base_query = Transaction.query.filter(Transaction.user_id == current_user.user_id)
        if time_type == "year":
            base_query = base_query.filter(func.year(Transaction.date) == year)
        else:
            base_query = base_query.filter(
                func.year(Transaction.date) == year,
                func.month(Transaction.date) == month
            )

        # 统计总收入、总支出
        total_income = float(
            base_query.filter(Transaction.type == "income").with_entities(func.sum(Transaction.amount)).scalar() or 0.0)
        total_expense = float(base_query.filter(Transaction.type == "expense").with_entities(
            func.sum(Transaction.amount)).scalar() or 0.0)

        # 统计总预算、预算剩余（总预算-总支出）
        budget_query = Budget.query.filter(
            Budget.user_id == current_user.user_id,
            Budget.year == year
        )
        if time_type == "month":
            # 月度预算：筛选指定月份
            budget_query = budget_query.filter(Budget.month == month)

        # 总预算（求和）
        total_budget = float(budget_query.with_entities(func.sum(Budget.total_budget)).scalar() or 0.0)
        budget_remaining = round(total_budget - total_expense, 2)

        return jsonify({
            "code": 200,
            "msg": "success",
            "data": {
                "total_income": round(total_income, 2),
                "total_expense": round(total_expense, 2),
                # 预算相关
                "total_budget": round(total_budget, 2),  # 总预算
                # "budget_remaining": budget_remaining,    # 总预算-总支出
                "balance": budget_remaining,  # 总预算-总支出
                "time_type": time_type,
                "year": year,
                "month": month if time_type == "month" else None
            }
        })
    except Exception as e:
        return jsonify({"code": 500, "msg": f"服务器错误：{str(e)}", "data": None}), 500


# 2. 分类收支占比分析
@statistics_bp.route('/category', methods=["GET"])
@token_required
def get_statistics_category(current_user):
    # 获取并校验请求参数
    time_type = request.args.get("time_type")
    year = request.args.get("year")
    month = request.args.get("month")
    trans_type = request.args.get("trans_type")

    if not all([time_type, year, trans_type]):
        return jsonify({
            "code": 400,
            "msg": "参数错误：time_type、year、trans_type 为必传项",
            "data": None
        }), 400

    if time_type not in ["month", "year"]:
        return jsonify({
            "code": 400,
            "msg": "time_type 必须为 'month' 或 'year'",
            "data": None
        }), 400
    if trans_type not in ["expense", "income"]:
        return jsonify({
            "code": 400,
            "msg": "trans_type 必须为 'expense' 或 'income'",
            "data": None
        }), 400

    if time_type == "month":
        if not month or not (1 <= int(month) <= 12):
            return jsonify({
                "code": 400,
                "msg": "month 为必填项，且需为 1-12 的整数",
                "data": None
            }), 400
        month = int(month)
    year = int(year)

    # 构建查询
    query = db.session.query(
        Category.id.label("category_id"),
        Category.name.label("category_name"),
        func.sum(Transaction.amount).label("category_total")
    ).join(
        Category, Transaction.category_id == Category.id
    ).filter(
        Transaction.user_id == current_user.user_id,
        Transaction.type == trans_type
    )

    # 按时间范围筛选
    if time_type == "year":
        query = query.filter(func.year(Transaction.date) == year)
    else:
        query = query.filter(
            func.year(Transaction.date) == year,
            func.month(Transaction.date) == month
        )

    query = query.group_by(Category.id, Category.name)
    category_stats = query.all()

    # 计算总金额和各分类占比
    total_amount = sum([item.category_total for item in category_stats]) if category_stats else 0.0
    result = []
    for item in category_stats:
        proportion = round((item.category_total / total_amount) * 100, 1) if total_amount != 0 else 0.0
        result.append({
            "category_id": item.category_id,
            "category_name": item.category_name,
            "amount": round(float(item.category_total), 2),
            "proportion": proportion
        })

    return jsonify({
        "code": 200,
        "msg": "success",
        "data": result,
        "summary": {
            "time_type": time_type,
            "year": year,
            "month": month if time_type == "month" else None,
            "trans_type": trans_type,
            "total_amount": round(float(total_amount), 2)
        }
    })


# 3. 收支趋势分析（按时间）
@statistics_bp.route('/trend', methods=["GET"])
@token_required
def get_statistics_trend(current_user):
    try:
        # 获取并校验请求参数
        time_type = request.args.get("time_type")
        start_date = request.args.get("start_date")
        end_date = request.args.get("end_date")
        trans_type = request.args.get("trans_type")

        if not all([time_type, start_date, end_date, trans_type]):
            return jsonify({
                "code": 400,
                "msg": "参数错误：time_type、start_date、end_date、trans_type 为必传项",
                "data": None
            }), 400

        if time_type not in ["day", "week", "month"]:
            return jsonify({
                "code": 400,
                "msg": "time_type 必须为 'day'、'week'、'month'",
                "data": None
            }), 400
        if trans_type not in ["expense", "income", "all"]:
            return jsonify({
                "code": 400,
                "msg": "trans_type 必须为 'expense'、'income'、'all'",
                "data": None
            }), 400

        # 日期格式校验与转换
        try:
            start_dt = datetime.strptime(start_date, "%Y-%m-%d")
            end_dt = datetime.strptime(end_date, "%Y-%m-%d")
            if start_dt > end_dt:
                return jsonify({
                    "code": 400,
                    "msg": "start_date 不能晚于 end_date",
                    "data": None
                }), 400
        except Exception as e:
            return jsonify({
                "code": 400,
                "msg": f"日期格式错误：{str(e)}",
                "data": None
            }), 400

        # 构建查询
        base_query = Transaction.query.filter(
            Transaction.user_id == current_user.user_id,
            Transaction.date >= start_dt,
            Transaction.date <= end_dt
        )

        if trans_type != "all":
            base_query = base_query.filter(Transaction.type == trans_type)

        # 按时间粒度分组
        if time_type == "day":
            base_query = base_query.with_entities(
                func.date(Transaction.date).label("period"),
                func.sum(Transaction.amount).label("total")
            ).group_by(func.date(Transaction.date))
        elif time_type == "week":
            base_query = base_query.with_entities(
                func.concat(func.year(Transaction.date), '-W', func.weekofyear(Transaction.date)).label("period"),
                func.sum(Transaction.amount).label("total")
            ).group_by(func.year(Transaction.date), func.weekofyear(Transaction.date))
        else:  # month
            base_query = base_query.with_entities(
                func.date_format(Transaction.date, "%Y-%m").label("period"),
                func.sum(Transaction.amount).label("total")
            ).group_by(func.year(Transaction.date), func.month(Transaction.date))

        trend_data = base_query.order_by("period").all()

        # 格式化结果
        result = [{
            "period": item.period,
            "total": round(float(item.total), 2) if item.total else 0.0
        } for item in trend_data]

        return jsonify({
            "code": 200,
            "msg": "success",
            "data": result,
            "summary": {
                "time_type": time_type,
                "start_date": start_date,
                "end_date": end_date,
                "trans_type": trans_type,
                "total_amount": round(sum(item["total"] for item in result), 2)
            }
        })
    except Exception as e:
        return jsonify({
            "code": 500,
            "msg": f"服务器错误：{str(e)}",
            "data": None
        }), 500


@statistics_bp.route("/custom-period", methods=["GET"])
@token_required
def get_custom_period_statistics(current_user):
    try:
        # 1. 参数验证
        user_id, start_dt, end_dt = _validate_request_params()
        end_dt_with_time = datetime(end_dt.year, end_dt.month, end_dt.day, 23, 59, 59)

        # 2. 计算统计数据
        overview = _calculate_overview(user_id, start_dt, end_dt_with_time)
        category_stats = _calculate_category_stats(user_id, start_dt, end_dt_with_time)  # 分类占比核心逻辑
        trend_data = _generate_trend_data(user_id, start_dt, end_dt, end_dt_with_time)

        # 3. 构造响应
        return jsonify({
            "code": 200,
            "msg": "success",
            "data": {
                "overview": overview,
                "category_stats": category_stats,  # 确保分类占比数据存在
                "trend": trend_data
            }
        })

    except Exception as e:
        # logger.error(f"统计错误: {traceback.format_exc()}")
        return jsonify({
            "code": 500,
            "msg": f"服务器错误: {str(e)}",
            "data": None
        }), 500


def _calculate_category_stats(user_id, start_dt, end_dt_with_time):
    """计算收入和支出的分类占比"""

    def _calculate_single_type(type_name):
        # 1. 查询该类型下各分类的总金额
        category_query = db.session.query(
            Category.id.label("category_id"),
            Category.name.label("category_name"),
            func.sum(Transaction.amount).label("total_amount")
        ).join(
            Transaction, Category.id == Transaction.category_id
        ).filter(
            Transaction.user_id == user_id,
            Transaction.type == type_name,
            Transaction.date >= start_dt,
            Transaction.date <= end_dt_with_time
        ).group_by(
            Category.id, Category.name
        ).order_by(
            func.sum(Transaction.amount).desc()
        )

        categories = category_query.all()
        if not categories:
            return []

        # 2. 计算总金额（转换为float类型）和占比
        total = sum(float(item.total_amount) for item in categories)  # 关键修改：统一为float

        # 3. 构造返回数据
        return [
            {
                "category_id": item.category_id,
                "category_name": item.category_name,
                "amount": round(float(item.total_amount), 2),
                "proportion": round((float(item.total_amount) / total) * 100, 1)  # 现在都是float类型
            } for item in categories
        ]

    # 分别计算收入和支出的分类占比
    return {
        "expense": _calculate_single_type("expense"),  # 支出分类占比
        "income": _calculate_single_type("income")  # 收入分类占比
    }


# 其他辅助函数保持不变
def _validate_request_params():
    # 验证user_id、start_date、end_date的有效性
    user_id_str = request.args.get("user_id")
    start_date = request.args.get("start_date")
    end_date = request.args.get("end_date")

    if not all([user_id_str, start_date, end_date]):
        raise ValueError("user_id、start_date、end_date为必传参数")

    try:
        user_id = int(user_id_str)
        start_dt = datetime.strptime(start_date, "%Y-%m-%d")
        end_dt = datetime.strptime(end_date, "%Y-%m-%d")
        if start_dt > end_dt:
            raise ValueError("开始日期不能晚于结束日期")
        return user_id, start_dt, end_dt
    except (ValueError, TypeError):
        raise ValueError("参数格式错误，user_id应为整数，日期格式为YYYY-MM-DD")


def _calculate_overview(user_id, start_dt, end_dt_with_time):
    # 计算总收入、总支出、结余等概览数据
    total_income = db.session.query(
        func.sum(Transaction.amount)
    ).filter(
        Transaction.user_id == user_id,
        Transaction.type == "income",
        Transaction.date.between(start_dt, end_dt_with_time)
    ).scalar() or 0.0
    # 确保转换为float类型
    total_income = float(total_income)

    total_expense = db.session.query(
        func.sum(Transaction.amount)
    ).filter(
        Transaction.user_id == user_id,
        Transaction.type == "expense",
        Transaction.date.between(start_dt, end_dt_with_time)
    ).scalar() or 0.0
    # 确保转换为float类型
    total_expense = float(total_expense)

    return {
        "total_income": round(total_income, 2),
        "total_expense": round(total_expense, 2),
        "balance": round(total_income - total_expense, 2),  # 现在都是float类型，可以正常运算
        "start_date": start_dt.strftime("%Y-%m-%d"),
        "end_date": end_dt_with_time.strftime("%Y-%m-%d"),
        "days": (end_dt_with_time.date() - start_dt.date()).days + 1
    }


def _generate_trend_data(user_id, start_dt, end_dt, end_dt_with_time):
    # 生成按天的收支趋势数据
    trend_query = db.session.query(
        func.date_format(Transaction.date, "%Y-%m-%d").label("date"),
        func.sum(case((Transaction.type == "income", Transaction.amount), else_=0)).label("income"),
        func.sum(case((Transaction.type == "expense", Transaction.amount), else_=0)).label("expense")
    ).filter(
        Transaction.user_id == user_id,
        Transaction.date.between(start_dt, end_dt_with_time)
    ).group_by(func.date_format(Transaction.date, "%Y-%m-%d"))

    trend_map = {item.date: item for item in trend_query.all()}

    # 生成完整日期列表（确保连续）
    date_list = []
    current_date = start_dt.date()
    while current_date <= end_dt.date():
        date_str = current_date.strftime("%Y-%m-%d")
        date_data = trend_map.get(date_str)
        date_list.append({
            "date": date_str,
            "income": round(float(date_data.income), 2) if date_data else 0.0,
            "expense": round(float(date_data.expense), 2) if date_data else 0.0
        })
        current_date += timedelta(days=1)

    return {
        "trend_type": "day",
        "data": date_list
    }